import random
import math
import re
from typing import List, Tuple, Dict, Optional
import time
from algorithm.geneticAlgorithm.Genetic2 import dijkstra
from algorithm.geneticAlgorithm.Genetic2.genetical import TGP_GA

from typing import List, Tuple


def key_node(is_key, start, goal):
    n = []
    for i in range(len(is_key)):
        if is_key[i] or i == start or i == goal:
            n.append(i)
    return n


class GeneticSolver:
    def __init__(self, start_node, goal_node, is_key, cost_e,
                 packNum=5, maxGen=100, Hayflick=4, mutationP=0.04, crossP=0.7):
        self.start_node = start_node
        self.goal_node = goal_node
        self.is_key = is_key
        self.cost_e = cost_e
        self.pack_num = packNum
        self.max_gen = maxGen
        self.hay_flick = Hayflick
        self.mutationP = mutationP
        self.crossP = crossP
        self.base = maxGen
        self.dis_map = {}  # 存储节点间的最短路径
        self.path_map = {}  # 存储节点间最短路经过的路径
        # 确定关键节点的集合
        self.n = key_node(self.is_key, self.start_node, self.goal_node)
        # 迪杰斯特拉算法计算节点间的最短路径，存到self.dis_map中
        for i in self.n:
            self.dis_map[i] = {}
            self.path_map[i] = {}
            dij_map = dict(dijkstra.dijkstra(self.n, cost_e))
            for j in self.n:
                if i != j:
                    self.dis_map[i][j] = dij_map[(i, j)][0]
                    self.path_map[i][j] = dij_map[(i, j)][1]
                # else:
                #     self.dis_map[i][j] = 0.0
                #     self.path_map[i][j] = [i, j]
        # 实例化TSP的类
        # print(self.dis_map)
        self.tsp_ga = TGP_GA(self.start_node, self.goal_node, self.pack_num, self.max_gen, self.hay_flick,
                             self.mutationP, self.crossP, self.n, self.dis_map)

    def run(self):
        self.tsp_ga.run()

    def get_best_path(self):
        _, path = self.tsp_ga.get_best_solution()
        return self.revert_path(path)

    def revert_path(self, origin_path):
        out_path = []
        for i in range(len(origin_path)):
            path = self.path_map[origin_path[i]][origin_path[i + 1]]
            out_path.extend(path[:])
        out_path.append(origin_path[-1])
        return out_path

    def get_display_data(self):
        data = self.tsp_ga.displays
        return [self.path_map, data]
